﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
//
using InterfaceLibrary;

namespace Controller
{
    public static class SortController
    {
        #region Fields
        //  Fields

        //  - static event to notify subscriber(s) of completed sort
        //  - empty delegate assignment prevents checking for (OnSortCompleted != null)
        //    prior to raising event
        public static event EventHandler<SortCompletedEventArgs> OnSortCompleted = delegate { };

        //  initialized to avoid checking for null
        static Dictionary<string, ISorter> sorters = 
            new Dictionary<string, ISorter> ( );
        #endregion

        #region Constructors
        //  Constructors

        static SortController( )
        {
            //  initialize running sorters collection
            RunningSorters = new List<string>( );
        }
        #endregion

        #region Functions
        //  Functions

        /// <summary>
        /// Instantiates three specific sort algorithms
        ///     - InsertionSort
        ///     - QuickSort
        ///     - MergeSort
        /// </summary>
        /// <param name="Source">An enumerable collection of Int32</param>
        public static void CreateSorters ( IEnumerable<int> Source )
        {
            if (sorters.Keys.Count > 0)
            { sorters.Clear( ); }

            //  instance sorters, converting IEnumerable to Array
            sorters.Add ( "InsertionSort", new InsertionSort.InsertionSorter ( Source.ToArray ( ) ) );
            sorters.Add ( "QuickSort", new QuickSort.QuickSorter ( Source.ToArray ( ) ) );
            sorters.Add ( "MergeSort", new MergeSort.MergeSorter ( Source.ToArray ( ) ) );

            //  update our list of sorter algorithm names
            SorterList = sorters.Keys;

            //  re-initialize running sorters collection
            RunningSorters = new List<string>( );
        }
        /// <summary>
        /// Starts all sort algorithms.
        /// </summary>
        public static void StartSorters ( )
        {
            //  if CreateSorters has not been called, there will be no registered sorters
            foreach (var kvEntry in sorters)
            {
                StartSorter(kvEntry.Key);
            }
        }
        /// <summary>
        /// Starts a single sort algorithm by sorter name.
        /// </summary>
        /// <param name="SorterName">Name of sorter algorithm.</param>
        public static void StartSorter(string SorterName)
        {
            //  find sorter kv pair
            KeyValuePair<string, ISorter> sorter = sorters.Where(kv => kv.Key == SorterName)
                                                          .FirstOrDefault( );

            if (sorter.Value != null)
            {
                //  KeyValuePair<string, ISorter> extension method
                sorter.Sort( );
            }
        }

        //  WaitCallback method
        static void DoSort ( object sortInfo )
        {
            //  retrieve SortInfo object
            var info = (SortInfo)sortInfo;

            //  invoke sort method
            info.Invoker.Invoke ( );

            //  raise event
            OnSortCompleted ( info, new SortCompletedEventArgs ( info ) );

            //  remove from running sorters list
            RunningSorters.Remove(info.Sorter.Key);
        }

        //  AsyncCallback method
        static void SortCompleted ( IAsyncResult iaResult )
        {
            //  retrieve SortInfo object from IAsyncResult
            var info = (SortInfo)iaResult.AsyncState;

            //  delegate - EndInvoke
            info.Invoker.EndInvoke ( iaResult );

            //  raise event
            OnSortCompleted ( info, new SortCompletedEventArgs ( info ) );

            //  remove from running sorters list
            RunningSorters.Remove(info.Sorter.Key);
        }

        //  extension helper method extends KeyValuePair<string, ISorter> object
        static void Sort(this KeyValuePair<string, ISorter> sorter)
        {
            SortInfo info = new SortInfo
            {
                Collection = sorter.Value.SortedList,
                Invoker = sorter.Value.Sort,
                Sorter = sorter,
                Timer = new System.Diagnostics.Stopwatch( )
            };

            info.Timer.Start( );

            if (sorter.Key == "InsertionSort") 
            {
                // use ThreadPool to demonstrate WaitCallback
                ThreadPool.QueueUserWorkItem(new WaitCallback(DoSort), info);
            }
            else
            {
                //  BeginInvoke gets worker thread from ThreadPool
                info.Invoker.BeginInvoke(new AsyncCallback(SortCompleted), info);
            }

            RunningSorters.Add(sorter.Key);
        }
        #endregion

        #region Properties
        //  Properties

        /// <summary>
        /// List of instanced Sorter Algorithms by name.
        /// </summary>
        public static IEnumerable<string> SorterList
        {
            get;
            private set;
        }
        /// <summary>
        /// List Sorter Algorithms that are running.
        /// </summary>
        public static List<string> RunningSorters
        {
            get;
            private set;
        }
        #endregion
    }
}
